package com.topone.service.impl;

import com.google.common.base.Objects;
import com.topone.Converter.OrderMaster2OrderDTOConverter;
import com.topone.Enum.OrderStatusEnum;
import com.topone.Enum.PayStatusEnum;
import com.topone.Enum.ResultEnum;
import com.topone.Enum.TcUserCouponEnum;
import com.topone.Exception.FanZoneException;
import com.topone.Form.CouponOrderForm;
import com.topone.Form.OrderForm;
import com.topone.Utils.KeyUntil;
import com.topone.Utils.MathUtil;
import com.topone.Utils.ResultVOUntil;
import com.topone.VO.ResultVO;
import com.topone.dataObject.Mapper.OrderMasterMapper;
import com.topone.dataObject.OrderDetail;
import com.topone.dataObject.OrderMaster;
import com.topone.dataObject.TcCoupon;
import com.topone.dataObject.TcUserCoupon;
import com.topone.dto.CartDTO;
import com.topone.dto.CouponDTO;
import com.topone.dto.OrderDTO;
import com.topone.dto.TcUserCouponDTO;
import com.topone.repository.OrderDetailRepository;
import com.topone.repository.OrderMasterRepository;
import com.topone.repository.TcCouponRepository;
import com.topone.repository.TcUserCouponRepository;
import com.topone.service.OrderService;
import com.topone.service.PayService;
import com.topone.service.TcCouponService;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.annotations.Synchronize;
import org.hibernate.criterion.Order;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;

import javax.transaction.Transactional;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by Administrator on 2017/12/4,0004.
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMasterRepository orderMasterRepository;
    @Autowired
    private OrderDetailRepository orderDetailRepository;
    @Autowired
    private TcCouponRepository tcCouponRepository;
    @Autowired
    private TcUserCouponRepository tcUserCouponRepository;
    @Autowired
    private TcCouponService tcCouponService;
    @Autowired
    private PayService payService;
    @Autowired
    private OrderMasterMapper orderMasterMapper;


    @Override
    @Transactional
    public OrderDTO create(CouponOrderForm couponOrderForm) {
        String orderId = KeyUntil.getUniqueKey();// 生成订单编号
        OrderDTO orderDTO = new OrderDTO();
        TcCoupon tcCoupon = tcCouponRepository.findOne(couponOrderForm.getCouponId());
        //1.获取订单详情(优惠券信息)
        OrderDetail orderDetail = generateOrderDetail(couponOrderForm, tcCoupon, orderId);
        List<OrderDetail> orderDetailList = new ArrayList<>();
        orderDetailList.add(orderDetail);
        orderDTO.setOrderDetailList(orderDetailList);
        try {
            orderDetailRepository.save(orderDetail);
        } catch (FanZoneException e) {
            log.error("【生成单据详情】失败 e={}", e.getMessage());
            throw new FanZoneException(ResultEnum.CREATE_ORDERDETAIL_ERROR);
        }
        log.info("【生成单据详情】成功 orderdetailId={}", orderDetail.getDetailId());
        //3.写入订单如数据库
        OrderMaster orderMaster = new OrderMaster();
        orderMaster.setOrderId(orderId);
        BeanUtils.copyProperties(couponOrderForm, orderMaster);
        orderMaster.setOrderAmount(new BigDecimal(couponOrderForm.getOrderAmount()));
        BeanUtils.copyProperties(orderMaster, orderDTO);
        log.info("{}", orderDTO);
        try {
            orderMasterRepository.save(orderMaster);
            log.info("【生成单据】成功 orderMaster={}", orderMaster.getOrderId());
        } catch (FanZoneException e) {
            log.error("【生成单据】失败 e={}", e.getMessage());
            throw new FanZoneException(ResultEnum.CREATE_ORDER_ERROR);
        }

        //4.扣库存
        List<CartDTO> cartDTOList = new ArrayList<>();
        cartDTOList = orderDTO.getOrderDetailList().stream()
                .map(e -> new CartDTO(e.getCouponId(), e.getCouponNum()))
                .collect(Collectors.toList());
        try {
            tcCouponService.decreaseStock(cartDTOList);
        } catch (FanZoneException e) {
            log.error("【生成单据扣库存】失败 e={}", e.getMessage());
            throw new FanZoneException(ResultEnum.REDUCE_COUPONNUM_ERROR);
        }
        log.info("【生成单据扣库存】成功 order={},orderDetailId={}", orderId);
        return orderDTO;
    }

    //订单生成时，生成订单详情
    private OrderDetail generateOrderDetail(CouponOrderForm couponOrderForm, TcCoupon tcCoupon, String orderId) {
        OrderDetail orderDetail = new OrderDetail();
        if (tcCoupon == null) {
            log.error("【创建订单详情】优惠券id不存在 coupon={}", tcCoupon);
            throw new FanZoneException(ResultEnum.COUPON_NOT_EXIT);
        }
        orderDetail.setOrderId(orderId);
        orderDetail.setDetailId(KeyUntil.getUniqueKey());
        BeanUtils.copyProperties(tcCoupon, orderDetail);
        orderDetail.setCouponNum(Integer.valueOf(couponOrderForm.getCouponNum()));
        return orderDetail;
    }

    @Override
    @Transactional
    public OrderDTO findOne(String orderId) {
        //根据orderId查询数据库里订单主表
        OrderMaster orderMaster = orderMasterRepository.findOne(orderId);
        if (orderMaster == null) {
            log.error("【查询单个订单失败】订单{}不存在", orderId);
            throw new FanZoneException(ResultEnum.ORDER_NOT_EXIST);
        }

        //根据orderId查询数据库订单详情表
        List<OrderDetail> orderDetailList = orderDetailRepository.findByOrderId(orderId);
        if (CollectionUtils.isEmpty(orderDetailList)) {
            log.error("【单个订单查询失败】订单详情{}不存在", orderId);
            throw new FanZoneException(ResultEnum.ORDERDETAIL_NOT_EXIST);
        }
        OrderDTO orderDTO = new OrderDTO();
        BeanUtils.copyProperties(orderMaster, orderDTO);
        orderDTO.setOrderDetailList(orderDetailList);
        return orderDTO;
    }

    @Override
    @Transactional
    public Page<OrderDTO> findList(String buyerOpenid, Pageable pageable) {
        Page<OrderMaster> orderMasterPage = orderMasterRepository.findByBuyerOpenid(buyerOpenid, pageable);
        List<OrderDTO> orderDTOList = OrderMaster2OrderDTOConverter.convert(orderMasterPage.getContent());
        Page<OrderDTO> orderDTOPage = new PageImpl<OrderDTO>(orderDTOList, pageable, orderMasterPage.getTotalElements());

        return orderDTOPage;
    }

    @Override
    @Transactional
    @Synchronized
    public OrderDTO cancel(OrderDTO orderDTO) {

        OrderMaster orderMaster = new OrderMaster();
        //如果订单已完结，不可取消
        if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) {
            log.error("【取消订单】订单状态不正确 orderId={}" +
                    "orderStatus={}", orderDTO.getOrderId(), orderDTO.getOrderStatus());
            throw new FanZoneException(ResultEnum.ORDER_STATUS_ERROR);
        }

        //修改订单状态
        orderDTO.setOrderStatus(OrderStatusEnum.CANCEL.getCode());
        BeanUtils.copyProperties(orderDTO, orderMaster);
        OrderMaster result = orderMasterRepository.save(orderMaster);
        if (result == null) {
            log.error("【取消订单】更新失败,orderMaster={}", orderMaster);
            throw new FanZoneException(ResultEnum.ORDER_UPDATE_FAIL);
        }

        //返还库存
        if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) {
            log.error("【取消订单】订单中无商品详情,orderDTO={}", orderDTO);
            throw new FanZoneException(ResultEnum.ORDER_DETAIL_EMPTY);
        }

        //遍历orderDTO中订单详情到cartDTOList中
        List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream()
                .map(e -> new CartDTO(e.getCouponId(), e.getCouponNum()))
                .collect(Collectors.toList());
        tcCouponService.increaseStock(cartDTOList);


        //退款
        if (orderDTO.getPayStatus().equals(PayStatusEnum.SUCCESS.getCode())) {
            payService.refund(orderDTO);
        }
        return orderDTO;
    }

    @Override
    @Transactional
    @Synchronized
    public OrderDTO finish(OrderDTO orderDTO) {
        OrderMaster orderMaster = new OrderMaster();
        //如果订单已完结 不可完结
        if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) {
            log.error("【订单完结】订单状态不正确 orderId={},orderStatus={}",
                    orderDTO.getOrderId(), orderDTO.getOrderStatus());
            throw new FanZoneException(ResultEnum.ORDER_STATUS_ERROR);
        }
        //修改状态
        orderDTO.setOrderStatus(OrderStatusEnum.FINISH.getCode());
        BeanUtils.copyProperties(orderDTO, orderMaster);
        OrderMaster result = orderMasterRepository.save(orderMaster);
        if (result == null) {
            log.error("【订单完结取消】更新失败,orderMaster={}", orderMaster);
            throw new FanZoneException(ResultEnum.ORDER_UPDATE_FAIL);
        }
        return orderDTO;
    }

    @Override
    @Transactional
    @Synchronized
    public OrderDTO paid(OrderDTO orderDTO) {

        //判断订单状态
        if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) {
            log.error("【订单支付完成】订单状态不正确，orderId={},orderStatus={}", orderDTO.getOrderId(),
                    orderDTO.getOrderStatus());
            throw new FanZoneException(ResultEnum.ORDER_STATUS_ERROR);
        }
        //判断支付状态
        if (orderDTO.getPayStatus().equals(PayStatusEnum.SUCCESS)) {
            log.error("【订单支付完成】订单支付状态不正确 orderDto={}", orderDTO);
            throw new FanZoneException(ResultEnum.ORDER_PAY_STATUS_ERROR);

        }
        //修改支付状态
        orderDTO.setPayStatus(PayStatusEnum.SUCCESS.getCode());
        OrderMaster orderMaster = new OrderMaster();
        BeanUtils.copyProperties(orderDTO, orderMaster);
        OrderMaster result = orderMasterRepository.save(orderMaster);
        if (result == null) {
            log.error("【订单支付完成】更新失败 orderMaster={}", orderMaster);
            throw new FanZoneException(ResultEnum.ORDER_UPDATE_FAIL);
        }
        //修改优惠券订单状态
        finish(orderDTO);

        //生成用户优惠券
        List<OrderDetail> orderDetailList = orderDetailRepository
                .findByOrderId(orderDTO.getOrderId());
        TcUserCoupon tcUserCoupon = new TcUserCoupon();
        for (OrderDetail orderDetail : orderDetailList) {
            TcUserCouponDTO tcUserCouponDTO = new TcUserCouponDTO();
            BeanUtils.copyProperties(orderDetail, tcUserCouponDTO);
            TcCoupon tcCoupon = tcCouponService.findOne(orderDetail.getCouponId());
            tcUserCouponDTO.setBussinessId(tcCoupon != null ? tcCoupon.getBussinessId() : "");
            tcUserCouponDTO.setCreateTime(new Date());
            tcUserCouponDTO.setUpdateTime(new Date());
            tcUserCouponDTO.setId(KeyUntil.getUniqueKey());
            tcUserCouponDTO.setBuyerOpenid(orderDTO.getBuyerOpenid());
            tcUserCouponDTO.setStatus("A");
            tcUserCouponDTO.setUseStatus(TcUserCouponEnum.UNUSE.getCode());
            BeanUtils.copyProperties(tcUserCouponDTO, tcUserCoupon);
            TcUserCoupon couponresult = tcUserCouponRepository.save(tcUserCoupon);
            if (couponresult == null) {
                log.error("【生成用户优惠券】入库失败,tcUserCoupon={}", tcUserCoupon);
                throw new FanZoneException(ResultEnum.USERCOUPON_INSERT_FAIL);
            }
        }
        return orderDTO;
    }

    @Override
    public Page<OrderDTO> findList(Pageable pageable) {
        Page<OrderMaster> orderMasterPage = orderMasterRepository.findAll(pageable);
        List<OrderDTO> orderDTOList = OrderMaster2OrderDTOConverter.convert(orderMasterPage.getContent());
        return new PageImpl<>(orderDTOList, pageable, orderMasterPage.getTotalElements());
    }

    //下单未支付订单
    @Override
    public List<OrderDTO> findUnpayOrderList(String openid) {
        return orderMasterMapper.unpayOrderDTOList(openid);
    }

    @Override
    public Map<String, Object> calculateAmount(String couponId, String couponNum,
                                               String couponPrice, String couponAmount) {

        Map<String, Object> map = new HashMap<>();
        TcCoupon tcCoupon = tcCouponService.findOne(couponId);
        if (java.util.Objects.isNull(tcCoupon)) {
            log.info("未查询到优惠券信息,couponId={}", couponId);
            map.put("error", ResultVOUntil.error(1, couponId + ":未查询到优惠券信息"));
            map.put("flag","error");
            return map;
        }
        Double price = Double.valueOf(couponPrice);
        Integer num = Integer.valueOf(couponNum);
        if(price!= tcCoupon.getCouponPrice().doubleValue()) {
            log.info("优惠券价格不一致,couponId={},couponPrice={},price={}",
                    couponId, couponPrice, price);
            map.put("error", ResultVOUntil.error(1, couponId + ":" + couponPrice + "!=" + tcCoupon.getCouponPrice() + "-->优惠券单价不一致"));
            map.put("flag","error");
            return map;

        }
        //判断支付金额是否一致
        double amount = Double.valueOf(couponAmount);
        if (!MathUtil.equal(price * num, amount)) {
            log.info("支付总价不一致,couponAmount={},amount={}",
                    couponAmount, price * num);
            map.put("error", ResultVOUntil.error(1, couponId + ":" + couponAmount + "!=" + price * num + "-->优惠券价格不一致"));
            map.put("flag","error");
            return map;
        }
        map.put("success", ResultVOUntil.success(map));
        map.put("flag","success");
        return map;

    }
}

